module CSRsFile (
  input clk,
  input rst,

//normal csr r/w port
  input [11:0] csr_addr,
  input csr_read,
  input csr_write,
  input csr_set,
  input csr_clear,
  input [63:0] csr_wdata,
  output reg [63:0] csr_rdata,
//specific csr r/w port

  input raise_intr,
  input op_mret,


  input tim_int_req,

  input mtip_clear,
  input msip_i,
  input msip_valid_i,
  output msip_o,

  output mtip,

  output reg csr_mie_rdata,
//CSR mepc
  output reg [63:0] csr_mepc_rdata,
  input csr_mepc_write,
  input [63:0] csr_mepc_wdata,
//CSR mcause
  input csr_mcause_write,
  input [63:0] csr_mcause_wdata,
//CSR mtvec
  output reg [63:0] csr_mtvec_rdata

);
  localparam MSTATUS_ADDR = 12'h300;
  localparam MTVEC_ADDR = 12'h305;
  localparam MEPC_ADDR = 12'h341;
  localparam MCAUSE_ADDR = 12'h342;
  localparam MIE_ADDR = 12'h304;
  localparam MIP_ADDR = 12'h344;

  localparam MSTATUS_MIE = 3;
  localparam MSTATUS_MPIE = 7;
  localparam MIE_MTIE = 7;
  localparam MIP_MTIP = 7;
  localparam MIP_MSIP = 3;
  reg [63:0] mepc,mcause,mtvec,mstatus,mip,mie;

  assign mtip = mip[MIP_MTIP];
  assign msip_o = mip[MIP_MSIP];
  //csr read
  always @(*) begin
    csr_rdata = 64'b0;
    csr_mepc_rdata = mepc;
    csr_mtvec_rdata = mtvec;
    csr_mie_rdata = mstatus[MSTATUS_MIE];
    if(csr_read)
      case(csr_addr)
      MSTATUS_ADDR: csr_rdata = mstatus;
      MTVEC_ADDR: csr_rdata = mtvec;
      MEPC_ADDR: csr_rdata = mepc;
      MCAUSE_ADDR: csr_rdata = mcause;
      MIP_ADDR: csr_rdata = mip;
      MIE_ADDR: csr_rdata = mie;
      default: csr_rdata = 64'b0;
      endcase
  end
  //csr write
  always @(posedge clk) begin
    if(rst) begin
      mepc <= 64'b0;
      mcause <= 64'b0;
      mtvec <= 64'b0;
      mstatus <= 64'ha00001800;
    end else begin
      if(tim_int_req & mstatus[MSTATUS_MIE] & mie[MIE_MTIE]) mip[MIP_MTIP] <= 1'b1;
      if(mtip_clear) mip[MIP_MTIP] <= 1'b0;
      if(msip_valid_i) mip[MIP_MSIP] <= msip_i;
      if(csr_write) begin
        case(csr_addr)
        MSTATUS_ADDR:     mstatus <= csr_wdata;
        MTVEC_ADDR:       mtvec   <= csr_wdata;
        MEPC_ADDR:        mepc    <= csr_wdata;
        MCAUSE_ADDR:      mcause  <= csr_wdata;
        MIP_ADDR:         mip     <= csr_wdata;
        MIE_ADDR:         mie     <= csr_wdata;
        default: ;
        endcase
      end else if(csr_set) begin
        case(csr_addr)
        MSTATUS_ADDR:     mstatus <= mstatus | csr_wdata;
        MTVEC_ADDR:       mtvec   <= mtvec   | csr_wdata;
        MEPC_ADDR:        mepc    <= mepc    | csr_wdata;
        MCAUSE_ADDR:      mcause  <= mcause  | csr_wdata;
        MIP_ADDR:         mip     <= mip     | csr_wdata;
        MIE_ADDR:         mie     <= mie     | csr_wdata;
        default: ;
        endcase
      end else if(csr_clear) begin
        case(csr_addr)
        MSTATUS_ADDR:     mstatus <= mstatus &(~csr_wdata);
        MTVEC_ADDR:       mtvec   <= mtvec   &(~csr_wdata);
        MEPC_ADDR:        mepc    <= mepc    &(~csr_wdata);
        MCAUSE_ADDR:      mcause  <= mcause  &(~csr_wdata);
        MIP_ADDR:         mip     <= mip     &(~csr_wdata);
        MIE_ADDR:         mie     <= mie     &(~csr_wdata);
        default: ;
        endcase
      end
      if(csr_mepc_write) mepc <= csr_mepc_wdata;
      if(csr_mcause_write) mcause <= csr_mcause_wdata;
      if(raise_intr) begin 
        mstatus[MSTATUS_MPIE] <= mstatus[MSTATUS_MIE];
        mstatus[MSTATUS_MIE] <= 1'b0;
      end
      if(op_mret) begin
        mstatus[MSTATUS_MIE] <= mstatus[MSTATUS_MPIE];
        mstatus[MSTATUS_MPIE] <= 1'b1;
      end
    end
    
  end

endmodule
